package cz.data.domain.market.mapping.listener;

import cz.data.common.core.DataConstant;
import cz.data.common.rabbitmq.config.RabbitConstant;
import cz.data.common.utils.JsonCommon;
import cz.data.common.utils.ThrowableUtil;
import cz.data.domain.market.mapping.handler.TableApiHandlerMapping;
import cz.data.domain.market.mapping.handler.DataApiHandlerMapping;
import cz.data.domain.market.mapping.listener.event.ApiAccessLogEvent;
import cz.data.domain.market.mapping.listener.event.ApiEventType;
import cz.data.domain.market.mapping.listener.event.ApiReleaseEvent;
import cz.data.domain.market.mapping.listener.event.TableApiReleaseEvent;
import cz.data.domain.market.mapping.service.ApiLogService;
import cz.data.domain.market.model.dto.ApiLogDto;
import cz.data.domain.market.model.entity.DataApiEntity;
import cz.data.domain.market.model.entity.TableApiEntity;
import cz.data.domain.market.rpc.DataApiServiceFeign;
import cz.data.domain.market.rpc.TableApiFeign;
import cz.data.gateway.model.dto.RouteDefinitionDto;
import cz.data.gateway.model.utils.RouteDefinitionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Component
public class SpringEventListener {

    @Autowired
    private Environment environment;
    @Autowired
    private ApiLogService apiLogService;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private DataApiHandlerMapping dataApiHandlerMapping;
    @Autowired
    private DataApiServiceFeign dataApiServiceFeign;
    @Autowired
    private TableApiFeign tableApiFeign;
    @Autowired
    private TableApiHandlerMapping tableApiHandlerMapping;

    @EventListener(ApplicationReadyEvent.class)
    public void applicationReady(ApplicationReadyEvent event) {
        log.info("初始化动态接口");
        CompletableFuture.runAsync(() -> {
            List<DataApiEntity> releaseDataApiList = null;
            while (releaseDataApiList == null) {
                ThrowableUtil.throwable(() -> Thread.sleep(3000));
                log.info("尝试获取远程动态数据接口描述...");
                releaseDataApiList = ThrowableUtil.callable(() -> dataApiServiceFeign.getReleaseDataApiList(), false);
                if (CollectionUtils.isNotEmpty(releaseDataApiList)) {
                    releaseDataApiList.forEach(api -> dataApiHandlerMapping.registerMapping(api));
                }
            }
        }, taskExecutor).whenComplete((res, e) -> {
            if (Objects.nonNull(e)) {
                log.error("初始化动态数据接口出错: {}", e.getMessage());
            } else {
                log.info("初始化动态数据接口成功");
            }
        });
        CompletableFuture.runAsync(() -> {
            List<TableApiEntity> releaseTableApiList = null;
            while (releaseTableApiList == null) {
                ThrowableUtil.throwable(() -> Thread.sleep(3000));
                log.info("尝试获取远程表服务接口描述...");
                releaseTableApiList = ThrowableUtil.callable(() -> tableApiFeign.releaseTableApiList(), false);
                if (CollectionUtils.isNotEmpty(releaseTableApiList)) {
                    releaseTableApiList.forEach(api -> tableApiHandlerMapping.registerMapping(api));
                }
            }
        }, taskExecutor).whenComplete((res, e) -> {
            if (Objects.nonNull(e)) {
                log.error("初始化动态表服务接口出错: {}", e.getMessage());
            } else {
                log.info("初始化动态表服务接口成功");
            }
        });
    }


    @EventListener(ApiReleaseEvent.class)
    public void apiRelease(ApiReleaseEvent event) {
        String serverName = environment.getProperty("spring.application.name");
        DataApiEntity api = event.getApi();
        String uri = DataApiEntity.buildUrlPath(api.getApiVersion(), api.getApiUrl());
        RouteDefinitionDto route = RouteDefinitionUtils.createRouteDefinition(api.getId(), serverName,
                api.getReqMethod(), uri);
        boolean active = ApiEventType.Release.equals(event.getEventType());
        if (active) {
            route.activeRoute(DataConstant.TrueOrFalse.TRUE.getKey());
        } else {
            route.activeRoute(DataConstant.TrueOrFalse.FALSE.getKey());
        }
        route.description(api.getApiName());
        route.creator(api.getCreateBy());
        route.setOrder(489);
        rabbitTemplate.convertAndSend(RabbitConstant.TOPIC_EXCHANGE,
                RabbitConstant.TOPIC_GATEWAY_ADMIN_ROUTE, JsonCommon.toJson(route));
        log.info("接收到动态API发布事件, 推送网关路由规则: {} 状态: {}", uri, active);
    }

    @EventListener(TableApiReleaseEvent.class)
    public void apiRelease(TableApiReleaseEvent event) {
        //todo table api使用前缀匹配路由 不需要发布到网关
    }

    @EventListener(ApiAccessLogEvent.class)
    public void apiAccessLog(ApiAccessLogEvent event) {
        ApiLogDto log = event.getLog();
        CompletableFuture.runAsync(
                () -> apiLogService.saveApiLog(log), taskExecutor
        );
    }
}
